package com.apps.member.service.impl;

import com.apps.globals.global.service.IKupaGlobalService;
import com.apps.goods.model.po.KupaGoods;
import com.apps.goods.model.po.KupaGoodsComment;
import com.apps.goods.service.IKupaGoodsCommentService;
import com.apps.goods.service.IKupaGoodsService;
import com.apps.helper.ThreadContextHelper;
import com.apps.helper.UserConextHelper;
import com.apps.member.download.enums.DownloadAccountItemMinType;
import com.apps.member.download.model.po.KupaMemberDownloadAccount;
import com.apps.member.download.service.IKupaMemberDownloadAccountService;
import com.apps.member.event.sMemberEvent;
import com.apps.member.model.po.*;
import com.apps.member.dao.KupaMemberMapper;
import com.apps.member.service.*;
import com.apps.sannotation.constraints.*;
import com.apps.sannotation.keys.JoinKey;
import com.apps.sannotation.keys.TimeLockKey;
import com.apps.saspect.*;
import com.apps.sexctption.DataException;
import com.apps.sexctption.NullException;
import com.apps.sutils.StringUtils;
import com.apps.sworld.dao.impl.sDaoImpl;
import com.apps.thirdparty.email.service.IKupaMailSendService;
import com.apps.thirdparty.sms.service.IKupaSmsService;
import com.apps.vip.model.po.KupaVipGoods;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 大鹏
 * @since 2020-10-02
 */
@Slf4j
@Service
public class KupaMemberServiceImpl extends sDaoImpl<KupaMemberMapper, KupaMember> implements IKupaMemberService
{

    @Autowired
    private IKupaSmsService smsPlugs;

    @Autowired
    private IKupaMailSendService mailSendService;

    @Autowired
    private IKupaGlobalService globalService;

    @Autowired
    private IKupaMemberCollectGoodsService collectGoodsService;

    @Autowired
    private IKupaGoodsService goodsService;

    @Autowired
    private IKupaMemberBrowseGoodsService browseGoodsService;

    @Autowired
    private IKupaMemberBuyGoodsService buyGoodsService;

    @Autowired
    private IKupaGoodsCommentService commentGoodsService;

    @Autowired
    private IKupaMemberLikeGoodsService likeGoodsService;

    @Autowired
    private IKupaMemberDownloadAccountService downloadAccountService;

    @Autowired
    private IKupaMemberDownloadGoodsService downloadGoodsService;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private ApplicationContext applicationContext;
    /**
     * 每次免费下载缓存前缀
     */
    private String downloadFreeCountPrefix="freedownload_";

    @ThreadLock
    @Validated
    @Override
    public KupaMember mobileLogin(@Mobile @NoNull(errMsg = "手机号不能为空") @JoinKey String mobile,
                            @NoNull(errMsg = "验证码不能为空") @StrLen(min = 6,max = 6,errMsg = "验证码只能是6位") String validcode)
    {
        //验证验证码是否正确
        smsPlugs.validMobileCode(mobile,validcode);
        //验证用户是否存在
        KupaMember member=getOneByFieldValue("mobile",mobile);
        //没有就注册
        if(null == member)
        {
            member=new KupaMember();
            member.setMobile(mobile);
            member.setHead_photo(globalService.QueryMap().getString("facedef"));
            member.setNick_name("未设置");
            member.setLevel(0);
            member.setTotal_login_num(0);
            saveToDB(member);
        }
        //更新最后登录时间
        member.setGmt_last_login(LocalDateTime.now());
        //增加登录次数
        member.setTotal_login_num(member.getTotal_login_num()+1);
        //计算并设置用户是否vip到期
        member=calculationVipExpireAndSetting(member);
        //更新用户数据
        updateById(member);
        //登录赠送免费下载额度
        addDownloadFreeCountByToday(member.getId(), globalService.QueryMap().getInt("loginsenddownload"));
        //把当前登录用户缓存进session
        ThreadContextHelper.getSession().setAttribute(UserConextHelper.CURRENT_MEMBER_KEY,member);
        return member;
    }

    @ValidMethod
    @Override
    public KupaMember emailLogin(@Email @NoNull(errMsg = "邮箱不能为空") String email,
                           @NoNull(errMsg = "验证码不能为空") @StrLen(min = 6,max = 6,errMsg = "验证码只能是6位") String validcode)
    {
        mailSendService.validEmailCode(email,validcode);
        //验证用户是否存在
        KupaMember member=getOneByFieldValue("email",email);
        //没有就注册
        if(null == member)
        {
            member=new KupaMember();
            member.setEmail(email);
            member.setHead_photo(globalService.QueryMap().getString("facedef"));
            member.setTotal_login_num(0);
            saveToDB(member);
        }
        //更新最后登录时间
        member.setGmt_last_login(LocalDateTime.now());
        //增加登录次数
        member.setTotal_login_num(member.getTotal_login_num()+1);
        //计算并设置用户是否vip到期
        member=calculationVipExpireAndSetting(member);
        //更新用户数据
        updateById(member);
        //登录赠送免费下载额度
        addDownloadFreeCountByToday(member.getId(), globalService.QueryMap().getInt("loginsenddownload"));
        //把当前登录用户缓存进session
        ThreadContextHelper.getSession().setAttribute(UserConextHelper.CURRENT_MEMBER_KEY,member);
        return member;
    }

    @Override
    public KupaMember wxLogin(String openid, String nickname,String face,Integer sex)
    {
        KupaMember member=getOneByFieldValue("wx_openid",openid);
        //不存在就创建
        if(null == member)
        {
            member=new KupaMember();
            member.setWx_openid(openid);
            member.setNick_name(nickname);
            member.setSex(sex);
            member.setHead_photo(face);
            member.setTotal_login_num(0);
            saveToDB(member);
        }
        //更新最后登录时间
        member.setGmt_last_login(LocalDateTime.now());
        //增加登录次数
        member.setTotal_login_num(member.getTotal_login_num()+1);
        //计算并设置用户是否vip到期
        member=calculationVipExpireAndSetting(member);
        //更新用户数据
        updateById(member);
        //登录赠送免费下载额度
        addDownloadFreeCountByToday(member.getId(), globalService.QueryMap().getInt("loginsenddownload"));
        //把当前登录用户缓存进session
        ThreadContextHelper.getSession().setAttribute(UserConextHelper.CURRENT_MEMBER_KEY,member);
        return member;
    }

    @Override
    public KupaMember qqLogin(String openid, String nickname,String face,Integer sex)
    {
        KupaMember member=getOneByFieldValue("qq_openid",openid);
        //不存在就创建
        if(null == member)
        {
            member=new KupaMember();
            member.setQq_openid(openid);
            member.setNick_name(nickname);
            member.setSex(sex);
            member.setHead_photo(face);
            member.setTotal_login_num(0);
            saveToDB(member);
        }
        //更新最后登录时间
        member.setGmt_last_login(LocalDateTime.now());
        //增加登录次数
        member.setTotal_login_num(member.getTotal_login_num()+1);
        //计算并设置用户是否vip到期
        member= calculationVipExpireAndSetting(member);
        //更新用户数据
        updateById(member);
        //登录赠送免费下载额度
        addDownloadFreeCountByToday(member.getId(), globalService.QueryMap().getInt("loginsenddownload"));
        //把当前登录用户缓存进session
        ThreadContextHelper.getSession().setAttribute(UserConextHelper.CURRENT_MEMBER_KEY,member);
        return member;
    }

    @Override
    public void loginOut(Integer member_id) {

    }


    @ThreadLock
    @Override
    public int collectGoods(@JoinKey Integer member_id,@JoinKey Integer goods_id)
    {
        if(null != collectGoodsService.getOne(member_id,goods_id))
            throw new NullException("您已经收藏了该商品");
        //创建收藏记录
        collectGoodsService.saveToDB(member_id,goods_id);
        //更新商品被收藏数
        return goodsService.addCollectNumber(goods_id,1);
    }

    @ThreadLock
    @Override
    public int cancelCollectGoods(@JoinKey Integer member_id,@JoinKey Integer goods_id)
    {
        if(null == collectGoodsService.getOne(member_id,goods_id))
            throw new NullException("您还未收藏该商品");
        //删除收藏记录
        collectGoodsService.delete(member_id,goods_id);
        //更新商品被收藏总数
        return goodsService.addCollectNumber(goods_id,-1);
    }

    @ThreadLock
    @Override
    public int likeGoods(@JoinKey Integer member_id,@JoinKey Integer goods_id)
    {
        if(null != likeGoodsService.getOne(member_id,goods_id))
            throw new DataException("您已经点赞了该商品");
        //插入点赞记录
        likeGoodsService.saveToDB(member_id,goods_id);
        //修改商品被点赞次数
        return goodsService.addLikeNumber(goods_id,1);
    }
    @ThreadLock
    @Override
    public int cancelLikeGoods(@JoinKey Integer member_id,@JoinKey Integer goods_id)
    {
        if(null == likeGoodsService.getOne(member_id,goods_id))
            throw new DataException("您未点赞该商品");
        //插入点赞记录
        likeGoodsService.delete(member_id,goods_id);
        //修改商品被点赞次数
        return goodsService.addLikeNumber(goods_id,-1);
    }

    @Override
    public void bindMobile(Integer member_id, String mobile, String valid_code) {
        //验证验证码是否正确
        smsPlugs.validMobileCode(mobile,valid_code);
        //验证用户是否存在
        KupaMember member=getOneByFieldValue("mobile",mobile);
        if(null != member)
            throw new DataException("手机"+mobile+"已经被其它账号绑定");
        member = getOneById(member_id);
        if(!StringUtils.isEmpty(member.getMobile()))
            throw new DataException("您已经绑定了手机号");
        member.setMobile(mobile);
        updateById(member);
    }

    @Override
    public void bindEmail(Integer member_id, String email, String valid_code) {
        mailSendService.validEmailCode(email,valid_code);
        //验证用户是否存在
        KupaMember member=getOneByFieldValue("email",email);
        if(null != member)
            throw new DataException("邮箱"+email+"已经被其它账号绑定");
        member = getOneById(member_id);
        if(!StringUtils.isEmpty(member.getEmail()))
            throw new DataException("您已经绑定了邮箱");
        member.setEmail(email);
        updateById(member);
    }

    @Override
    public void bindWx(Integer member_id, String openid) {
        KupaMember member=getOneByFieldValue("wx_openid",openid);
        if(null != member)
            throw new DataException("该微信已经被其它账号绑定");
    }

    @Override
    public void bindQQ(Integer member_id, String openid) {

    }

    @ValidMethod
    @ThreadLock
    @Override
    public void modifyNickName(@JoinKey Integer member_id,@NoNull @StrLen(min=2,max =6,errMsg = "昵称最短2个字,最长6个字") String nickname) {
         KupaMember member=getOneById(member_id);
         member.setNick_name(nickname);
         updateById(member);
    }

    @ThreadLock
    @Override
    public void viewsGoods(@JoinKey Integer member_id,KupaGoods goods)
    {
//        if(null != browseGoodsService.getOne(member_id,goods.getId()))
//            return;
        KupaMemberBrowseGoods browseGoods= new KupaMemberBrowseGoods();
        browseGoods.setMember_id(member_id);
        browseGoods.setGoods_id(goods.getId());
        browseGoods.setGoods_cat_id(goods.getGoods_cat_id());
        browseGoodsService.saveToDB(browseGoods);
    }

    @ValidMethod
    @CallTimeLock
    @ThreadLock
    @Override
    public List<KupaGoodsComment> commentGoods(@TimeLockKey @JoinKey Integer member_id,
                                               @TimeLockKey @JoinKey Integer goods_id,
                                               @StrMaxLen(max = 200,errMsg = "最多只能评论200字") String context)
    {
        KupaMember member=getOneById(member_id);
        if(null == member)
            throw new NullException("用户"+member_id+"不存在");
        KupaGoodsComment commentGoods=new KupaGoodsComment();
        commentGoods.setMember_id(member_id);
        commentGoods.setGoods_id(goods_id);
        commentGoods.setContext(context);
        commentGoods.setMember_head_photo(member.getHead_photo());
        commentGoods.setMember_nickname(member.getNick_name());
        commentGoodsService.saveToDB(commentGoods);
        //修改商品被评论次数
        goodsService.addCommentNumber(goods_id,1);
        return commentGoodsService.queryByMemberId(member_id);
    }


    @Override
    public IPage<KupaGoods> pageQueryGoodsByHistoryBrows(Integer member_id, Integer goods_cat_id,int pageNo, int pageSize)
    {
        IPage<KupaGoods> result=new Page<KupaGoods>();
        result.setRecords(new ArrayList<>());
        List<KupaMemberBrowseGoods> collectGoods=goods_cat_id.intValue()==0?browseGoodsService.pageQueryByMemberId(member_id,pageNo,pageSize).getRecords()
                                                 :browseGoodsService.pageQueryByMemberId(member_id,pageNo,pageSize,new QueryWrapper<KupaMemberBrowseGoods>().eq("goods_cat_id",goods_cat_id)).getRecords();
        for(KupaMemberBrowseGoods goods:collectGoods)
            result.getRecords().add(goodsService.getOneById(goods.getGoods_id()));
        return result;
    }

    @Override
    public IPage<KupaGoods> pageQueryGoodsByOwnBuys(Integer member_id,Integer goods_cat_id,int pageNo, int pageSize)
    {
        IPage<KupaGoods> result=new Page<KupaGoods>();
        result.setRecords(new ArrayList<>());
        List<KupaMemberBuyGoods> collectGoods=goods_cat_id.intValue()==0?buyGoodsService.pageQueryByMemberId(member_id,pageNo,pageSize).getRecords()
                                              :buyGoodsService.pageQueryByMemberId(member_id,pageNo,pageSize,new QueryWrapper<KupaMemberBuyGoods>().eq("goods_cat_id",goods_cat_id)).getRecords();
        for(KupaMemberBuyGoods goods:collectGoods)
            result.getRecords().add(goodsService.getOneById(goods.getGoods_id()));
        return result;
    }

    @Override
    public IPage<KupaGoods> pageQueryGoodsByCollect(Integer member_id,Integer goods_cat_id, int pageNo, int pageSize)
    {
        IPage<KupaGoods> result=new Page<KupaGoods>();
        result.setRecords(new ArrayList<>());
        List<KupaMemberCollectGoods> collectGoods=goods_cat_id.intValue()==0?collectGoodsService.pageQueryByMemberId(member_id,pageNo,pageSize).getRecords()
                                                  :collectGoodsService.pageQueryByMemberId(member_id,pageNo,pageSize,new QueryWrapper<KupaMemberCollectGoods>().eq("goods_cat_id",goods_cat_id)).getRecords();
        for(KupaMemberCollectGoods goods:collectGoods)
            result.getRecords().add(goodsService.getOneById(goods.getGoods_id()));
        return result;
    }

    @Override
    public IPage<KupaGoods> pageQueryGoodsByDownload(Integer member_id,Integer goods_cat_id, int pageNo, int pageSize)
    {
        IPage<KupaGoods> result=new Page<KupaGoods>();
        result.setRecords(new ArrayList<>());
        List<KupaMemberDownloadGoods> collectGoods=goods_cat_id.intValue()==0?downloadGoodsService.pageQueryByMemberId(member_id,pageNo,pageSize).getRecords()
                                                   :downloadGoodsService.pageQueryByMemberId(member_id,pageNo,pageSize,new QueryWrapper<KupaMemberDownloadGoods>().eq("goods_cat_id",goods_cat_id)).getRecords();
        for(KupaMemberDownloadGoods goods:collectGoods)
            result.getRecords().add(goodsService.getOneById(goods.getGoods_id()));
        return result;
    }

    @Override
    public void openingVip(Integer member_id, KupaVipGoods vipGoods)
    {
        //开通VIP
        KupaMember member=getOneById(member_id);
        if(null == member)
            throw new NullException("用户"+member_id+"不存在");
        member = calculationVipExpireAndSetting(member);
        if(isVip(member))
            throw new DataException("用户"+member.getId()+"已经是vip");
        member.setLevel(vipGoods.getDays().intValue()==10000?2:1);
        member.setGmt_vip_expire(member.getGmt_vip_expire().plusDays(vipGoods.getDays()));
        member.setVip_days_remaining(vipGoods.getDays());
        member.setLevel_name(vipGoods.getName());
        //更新用户数据
        updateById(member);
    }

    @Override
    public boolean isVip(Integer member_id)
    {
        KupaMember member=getOneById(member_id);
        if(null == member)
            throw new NullException("用户"+member_id+"不存在");
        if(member.getLevel().intValue() > 0)
            return true;
        return false;
    }

    @ValidMethod
    @Override
    public boolean isVip(@NoNull KupaMember member)
    {
        if(member.getLevel().intValue() > 0)
            return true;
        return false;
    }

    @ScriptEvent(script = sMemberEvent.class, beForeMethodName = "onDownload(member_id,goods_id)",afterMethodName = "onDownloaded(member_id,goods_id,result)")
    @Override
    public KupaGoods downloadGoods(Integer member_id,Integer goods_id)
    {
        KupaMember member=getOneById(member_id);

        if(null ==  member)
            throw new NullException("用户"+member_id+"不存在");
        KupaGoods goods=goodsService.getOneById(goods_id);
        if(null == goods)
            throw new NullException("商品"+goods_id+"不存在");

        //如果用户是会员则直接返回可以下载
        if(member.getLevel().intValue() > 0 )
            return goods;
        //如果已经单买了该商品也直接返回可以下载
        if(null != buyGoodsService.getOne(member_id,goods_id))
            return goods;
        //如果还有每日免费下载额度
        if(getDownloadFreeCountByMemberId(member_id)>0) {
            //每次下载次数-1
            subDownloadFreeCountByToday(member_id,1);
            return goods;
        }
        //如果还有赠送的免费下载额度
        if(downloadAccountService.getOneByMemberId(member_id).getAvailable_balance().intValue() > 0)
        {
            //免费下载次数-1
            downloadAccountService.Spend(member_id,1, DownloadAccountItemMinType.DOWNLOAD);
            return goods;
        }
        //都不满足则不能下载
        return null;
    }

    @Override
    public int getTotalDownloadFreeCountByMemberId(Integer member_id) {
        return getDownloadFreeCountByMemberId(member_id)+downloadAccountService.getOneByMemberId(member_id,new KupaMemberDownloadAccount()).getAvailable_balance().intValue();
    }

    /**
     * 增加用户的当日免费下载次数
     * @param member_id
     * @param count
     */
    private void addDownloadFreeCountByToday(Integer member_id,Integer count)
    {
        //如果今天已经赠送则不给予
        if(null != redisTemplate.opsForValue().get(downloadFreeCountPrefix+"status_"+member_id))
            return;
        //给予免费下载次数
         Integer number = (Integer) redisTemplate.opsForValue().get(downloadFreeCountPrefix+member_id);
         if(null == number)
             number = 0;
         //给与赠送次数
         redisTemplate.opsForValue().set(downloadFreeCountPrefix+member_id,number+count);
         //记录下今天已经赠送了
         redisTemplate.opsForValue().set(downloadFreeCountPrefix+"status_"+member_id,true);
    }

    /**
     * 减少用户的当日免费下载额度
     * @param member_id
     * @param count
     */
    private void subDownloadFreeCountByToday(Integer member_id,Integer count)
    {
        Integer number = (Integer) redisTemplate.opsForValue().get(downloadFreeCountPrefix+member_id);
        if(null == number)
            return;
        if(number.intValue() - count.intValue() <= 0)
            throw new DataException("今日免费下载额度已经用完");
        redisTemplate.opsForValue().set(downloadFreeCountPrefix+member_id,number-count);
    }

    /**
     * 获取每日免费下载次数剩余额度
     * @param member_id
     * @return
     */
    private int getDownloadFreeCountByMemberId(Integer member_id)
    {
        Integer number = (Integer) redisTemplate.opsForValue().get(downloadFreeCountPrefix+member_id);
        if(null == number)
            number = 0;
        return number;
    }
    /**
     * 计算vip剩余天数和设置是否到期
     * @param member
     * @return
     */
    private KupaMember calculationVipExpireAndSetting(KupaMember member)
    {
        //不是会员直接返回
        if(member.getLevel().intValue() == 0 || member.getLevel().intValue() == 2)
            return member;
        //如果是会员但到期时间为空则报错
        if(member.getLevel().intValue() > 0 && null == member.getGmt_vip_expire())
            throw new NullException("会员"+member.getId()+"到期时间为空");
        //检测是否到期,如果到期设置vip等级为0
        if(LocalDateTime.now().isAfter(member.getGmt_vip_expire())) {
            member.setLevel(0);
            member.setLevel_name("普通用户");
        }
        //计算剩余天数
        int day=(int)(member.getGmt_vip_expire().toLocalDate().toEpochDay() - LocalDateTime.now().toLocalDate().toEpochDay());
        if(day < 0)
            day=0;
        member.setVip_days_remaining(day);
        return member;
    }
}
